package com.mdp.tpa.pay.wxpay.config;

import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
import com.wechat.pay.contrib.apache.httpclient.cert.CertificatesManager;
import com.wechat.pay.contrib.apache.httpclient.exception.HttpCodeException;
import com.wechat.pay.contrib.apache.httpclient.exception.NotFoundException;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import lombok.Data;
import org.apache.http.impl.client.CloseableHttpClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.Scheduled;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.PrivateKey;


@Configuration
//@PropertySource("classpath:wxpay.properties") //读取配置文件
@ConfigurationProperties(prefix="mdp.apps.wxpay3") //读取wxpay节点
@Data //使用set方法将wxpay节点中的值填充到当前类的属性中
public class WxpayConfig {

    private Logger log= LoggerFactory.getLogger(WxpayConfig.class);

    // 商户号
    private String mchId;

    // 商户API证书序列号
    private String mchSerialNo;

    // 商户私钥文件
    private String privateKeyPath;

    // APIv3密钥
    private String apiV3Key;

    // APPID
    private String appid;

    // 微信服务器地址
    private String domain;

    // 接收结果通知地址
    private String notifyDomain;

    // APIv2密钥，此版本不用
    //private String partnerKey;

    private Verifier verifier=null;



    private CloseableHttpClient wxPayClient=null;


    /**
     * 获取商户的私钥文件
     * @param path
     * @return
     */
    private PrivateKey getPrivateKey(String path){

        try {
            File file = new File(path);
            log.info("私钥路径为"+path);
            return PemUtil.loadPrivateKey(new FileInputStream(file));
        } catch (FileNotFoundException e) {
            throw new RuntimeException("私钥文件不存在", e);
        }
    }
    public Verifier getVerifier()  {
        if(verifier==null){
            try {
                this.verifier=this.initVerifier();
                return this.verifier;
            } catch (NotFoundException e) {
                log.error("初始化证书失败",e);
            } catch (IOException e) {
                log.error("初始化证书失败",e);
            }
        }
        return verifier;
    }

    public CloseableHttpClient getWxPayClient() {
        if(this.wxPayClient==null){
            this.wxPayClient=this.initWxPayClient(this.getVerifier());
            return this.wxPayClient;
        }
        return wxPayClient;
    }

    /**
     * 获取签名验证器
     * @return
     */
    public Verifier initVerifier() throws NotFoundException, IOException {

        log.info("获取签名验证器");

        //获取商户私钥
        PrivateKey privateKey = getPrivateKey(privateKeyPath);

        //私钥签名对象
        PrivateKeySigner privateKeySigner = new PrivateKeySigner(mchSerialNo, privateKey);

        //身份认证对象
        WechatPay2Credentials wechatPay2Credentials = new WechatPay2Credentials(mchId, privateKeySigner);

        // 获取证书管理器实例
        CertificatesManager certificatesManager = CertificatesManager.getInstance();

        // 向证书管理器增加需要自动更新平台证书的商户信息
        try{
            certificatesManager.putMerchant(mchId,
                    wechatPay2Credentials,
                    apiV3Key.getBytes(StandardCharsets.UTF_8));
        }catch (GeneralSecurityException | HttpCodeException e){
            e.printStackTrace();
        }

        Verifier verifier = certificatesManager.getVerifier(mchId);
        log.info("获取签名验证器的信息：ValidCertificate--"+verifier.getValidCertificate());
        log.info("获取签名验证器的信息：NotBefore--"+verifier.getValidCertificate().getNotBefore());
        log.info("获取签名验证器的信息：NotAfter--"+verifier.getValidCertificate().getNotAfter());
        log.info("获取签名验证器的信息：SubjectDN--"+verifier.getValidCertificate().getSubjectDN());
        log.info("获取签名验证器的信息：SerialNumber--"+verifier.getValidCertificate().getSerialNumber());
        log.info("获取签名验证器的信息：IssuerDN--"+verifier.getValidCertificate().getIssuerDN());
        return verifier;
    }


    /**
     * 获取http请求对象
     * @param verifier
     * @return
     */
    public CloseableHttpClient initWxPayClient(Verifier verifier){

        log.info("获取httpClient");

        //获取商户私钥
        PrivateKey privateKey = getPrivateKey(privateKeyPath);

        WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
                .withMerchant(mchId, mchSerialNo, privateKey)
                .withValidator(new WechatPay2Validator(verifier));
        // ... 接下来，你仍然可以通过builder设置各种参数，来配置你的HttpClient

        // 通过WechatPayHttpClientBuilder构造的HttpClient，会自动的处理签名和验签，并进行证书自动更新
        CloseableHttpClient httpClient = builder.build();

        return httpClient;
    }

    @Scheduled(cron = "30 10 2 * * ?")
    public void refreshCert(){
        try {
            log.info("自动更新证书开始---");
            this.verifier=this.initVerifier();
            log.info("自动更新证书结束");
        } catch (NotFoundException e) {
            log.error("初始化证书失败",e);
        } catch (IOException e) {
            log.error("初始化证书失败",e);
        }
        this.wxPayClient=this.initWxPayClient(this.verifier);
    }

}
